package info.rflow;

import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.BackingStoreException;
import java.util.prefs.Preferences;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * Some global static utility methods which are used here, there and everywhere in RFlow code-base.
 *
 * @author Holger Brandl
 */
public class Utils {


    public static final String PROP_STARTUP_COUNTER = "general.startup.counter";


    public synchronized static Preferences getPrefs() {
        return Preferences.userNodeForPackage(Utils.class);
//        if (prefs == null) {
//            prefs = Preferences.userNodeForPackage(RFlow.class);
//        }
//
//        return prefs;
    }


    public static void saveWindowBounds(String windowName, Component c) {
        getPrefs().putInt(windowName + ".xpos", (int) c.getLocation().getX());
        getPrefs().putInt(windowName + ".ypos", (int) c.getLocation().getY());
        getPrefs().putInt(windowName + ".width", c.getWidth());
        getPrefs().putInt(windowName + ".height", c.getHeight());
    }


    public static void restoreWindowBounds(String windowName, Component c) {
        c.setBounds(
                getPrefs().getInt(windowName + ".xpos", (int) c.getLocation().getX()),
                getPrefs().getInt(windowName + ".ypos", (int) c.getLocation().getY()),
                getPrefs().getInt(windowName + ".width", c.getWidth()),
                getPrefs().getInt(windowName + ".height", c.getHeight())
        );
    }


    public static void flushPreferences() {
        try {
            getPrefs().flush();
        } catch (BackingStoreException e) {
            e.printStackTrace();
        }
    }


    public static void resetAllSettings() {
        try {
            getPrefs().clear();
            getPrefs().flush();
        } catch (BackingStoreException e) {
            e.printStackTrace();
        }
    }


    /**
     * Returns the global translation bundle of RFlow.
     */
    public static ResourceBundle getRB() {
        // note: to start OC with another local just add the following vm properties: -Duser.language=de -Duser.country=DE
        Locale locale = Locale.getDefault();

        return ResourceBundle.getBundle("info.rflow.translation", locale);
    }


    public static void log(String msg) {
        log(Level.INFO, msg);
    }


    public static void log(Level level, String msg) {
        Logger.getLogger("rflow").log(level, msg);
    }


    public static boolean isWindowsPlatform() {
        String os = System.getProperty("os.name");
        return os != null && os.startsWith("Windows");
    }


    public static boolean isMacOSX() {
        String osName = System.getProperty("os.name");
        return osName.startsWith("Mac OS X");
    }


    public static boolean isLinux() {
        return !isWindowsPlatform() & !isMacOSX();
    }


    private static File copyFile(File inFile, File outFile) {
        try {
            assert inFile.isFile();
            assert outFile.getParentFile().isDirectory();

            InputStream is = new FileInputStream(inFile);
            copyStreamIntoFile(outFile, is);

            return outFile;
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }


    public static void copyStreamIntoFile(File outFile, InputStream is) throws IOException {
        OutputStream os = new FileOutputStream(outFile);

        byte[] buf = new byte[1024];
        int len;
        while ((len = is.read(buf)) > 0) {
            os.write(buf, 0, len);
        }

        is.close();
        os.close();
    }


    /**
     * Collects all files list which match ALL given filters.
     *
     * @param directory the base directory for the search
     * @param suffix
     * @return The list of all odp-files found in one of the subdirectories of <code>directory</code>.
     */
    public static java.util.List<File> findFiles(File directory, String suffix) {
        assert directory.isDirectory();

        java.util.List<File> allFiles = new ArrayList<File>();

        File[] files = directory.listFiles();
        for (File file : files) {
            if (file.isDirectory()) {
                allFiles.addAll(findFiles(file, suffix));
            } else {
                if (file.isFile() && file.getName().endsWith(suffix))
                    allFiles.add(file);
            }
        }

        Collections.sort(allFiles);
        return allFiles;
    }


    public static boolean isAllFalse(Collection<Boolean> booleans) {
        for (Boolean aBoolean : booleans) {
            if (aBoolean)
                return false;
        }

        return true;
    }


    public static void sleep(final int timeMs) {
        try {
            Thread.sleep(timeMs);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    public static URL loadResource(String resourceName) {
        if (Utils.class.getClass().getClassLoader() != null) {
            return Utils.class.getClass().getClassLoader().getResource(resourceName);
        } else {
            return Utils.class.getClassLoader().getResource("info/rflow/" + resourceName);
        }
    }


    public static void main(String[] args) throws IOException {
//        try {
//            for (String s : getPrefs().keys()) {
//                System.out.println("pref is : " + s + " and its value is " + getPrefs().get(s, "foobar"));
//            }
//        } catch (BackingStoreException e) {
//            e.printStackTrace();
//        }

        resetAllSettings();
//        flushPreferences();
        RFlow.main(null);

        // set pref for testing
//        getPrefs().putDouble("lalelu", 56);
    }


    public static File getUserHome() {
        return new File(System.getProperty("user.home"));
    }


    public static File getLayoutFile(File saveFilePath) {
        if (saveFilePath == null)
            return null;

        return new File(saveFilePath.getParent().toString() + File.separatorChar + "." + saveFilePath.getName() + ".layout");
    }


    public static String extractGroup(String curLine, String pattern) {
        Matcher matcher = Pattern.compile(pattern, Pattern.MULTILINE).matcher(curLine);
        if (matcher.find()) {
            return matcher.group(1);
        } else {
            return null;
        }
    }


    public static String stripHashCharLines(String script) {
        Matcher m = Pattern.compile("(^[#]+$)").matcher(script);
        while (m.find()) {
            // replace first number with "number" and second number with the first
            script = script.replaceFirst("(^[#]+$)", "");
        }

        return script;
    }


    public static String uncommentLoadStatements(String script) {
        Matcher m = Pattern.compile("(# print[(]load)").matcher(script);
        while (m.find()) {
            script = script.replaceFirst("# print[(]load", "print(load");
        }

        m = Pattern.compile("(# load)").matcher(script);
        while (m.find()) {
            script = script.replaceFirst("# load", "load");
        }

        return script;
    }


    public static void warnMissingWD() {
        String errosMsg = "RFlow requires a working directory to be set for the graph. Either set it manually or add a setwd('/my/working/dir') statement to your script file";
        JOptionPane.showMessageDialog(null, errosMsg, "Could not execute workflow", JOptionPane.WARNING_MESSAGE);
    }


    private static Random ranGen;


    public static Random getRanGen() {
        if (ranGen == null)
            ranGen = new Random();

        return ranGen;
    }
}

